/**
 * author      : dormi330
 * date        : 2018/6/26
 * project     : mybatis
 * description : 应用层服务
 */

package com.deep.trade.application.order;

import com.deep.trade.adaptor.required.IdService;
import com.deep.trade.adaptor.required.MemberAddress;
import com.deep.trade.adaptor.required.inventory.DtoAssureInventory;
import com.deep.trade.adaptor.required.member.Member;
import com.deep.trade.adaptor.required.member.MemberService;
import com.deep.trade.domain.order.CommandPlaceOrder;
import com.deep.trade.infrastructure.utils.CommonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.deep.trade.adaptor.required.inventory.InventoryService;
import com.deep.trade.common.TradeException;
import com.deep.trade.order.InDtoCreateOrder;
import com.deep.trade.order.InDtoCreateOrder.InDtoOrderItem;

@Service
public class PlaceOrderService {

    @Autowired
    private IdService idService;

    @Autowired
    private MemberService memberService;

    @Autowired
    private CommandPlaceOrder commandPlaceOrder;

    @Autowired
    private InventoryService inventoryService;

    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    /**
     * 新建订单
     *
     * @param inDtoCreateOrder 创建订单的入参
     * @return 订单创建成功与否
     * @throws Exception
     */
    public void placeOrder(InDtoCreateOrder inDtoCreateOrder) throws Exception {
        logger.info("{}, {}", CommonUtils.currentClassAndMethod(), inDtoCreateOrder);

        if (inDtoCreateOrder == null) throw new TradeException("input arguments cannot be null");

        String tenantCode = inDtoCreateOrder.getTenantCode();
        if (null == tenantCode) throw new TradeException("tenantCode cannot be null");

        String memberId = inDtoCreateOrder.getMemberId();
        if (null == memberId) throw new TradeException("memberId cannot be null");

        // 确保库存足量
        DtoAssureInventory dtoAssureInventory = new DtoAssureInventory();
        dtoAssureInventory.setReqId(idService.uuid());
        dtoAssureInventory.setTenantCode(inDtoCreateOrder.getTenantCode());
        for (InDtoOrderItem inDtoOrderItem : inDtoCreateOrder.getOrderItemList()) {
            dtoAssureInventory.addItem(inDtoOrderItem.getSkuId(), inDtoOrderItem.getQuantity());
        }
        boolean inventoryOk = inventoryService.subInventory(dtoAssureInventory);
        if (!inventoryOk) {
            inventoryService.addInventory(dtoAssureInventory);
            throw new TradeException("inventory not fulfil");
        }

        Member member = assureMember(tenantCode, memberId);
        if (null == member) throw new TradeException("member not exists");
        MemberAddress address = assureMemberAddress(tenantCode, member.getId(), inDtoCreateOrder.getAddressId());
        if (null == address) throw new TradeException("member address not exists");

        try {
            commandPlaceOrder.placeOrder(tenantCode, member, address, inDtoCreateOrder.getRemark(), inDtoCreateOrder.getOrderItemList());
        } catch (Exception ex) {
            logger.error("下单失败");
            ex.printStackTrace();
            throw new TradeException("fail to place order");
        }
    }

    /**
     * 获取会员并确保正常
     *
     * @param tenantCode
     * @param memberId
     * @return
     * @throws Exception
     */
    private Member assureMember(String tenantCode, String memberId) throws Exception {
        if (null == tenantCode) throw new TradeException("tenantCode cannot be null");
        if (null == memberId) throw new TradeException("memberId cannot be null");

        Member member = memberService.memberOfId(tenantCode, memberId);
        if (member == null) {
            String errMsg = String.format("no such member, tenantCode=%s,  memberId=%s", tenantCode, memberId);
            throw new TradeException(errMsg);
        }
        return member;
    }

    /**
     * 获取会员地址并确保正常
     *
     * @param tenantCode
     * @param memberId
     * @param addressId
     * @return
     * @throws Exception
     */
    private MemberAddress assureMemberAddress(String tenantCode, String memberId, String addressId) throws Exception {
        if (null == tenantCode) throw new TradeException("tenantCode cannot be null");
        if (null == memberId) throw new TradeException("memberId cannot be null");
        if (null == addressId) throw new TradeException("addressId cannot be null");

        MemberAddress memberAddress = memberService.addressOfMember(tenantCode, memberId, addressId);
        if (memberAddress == null) {
            String errMsg = String.format("no such memberAddress, tenantCode=%s,  memberId=%s, addressId=%s", tenantCode, memberId, addressId);
            throw new TradeException(errMsg);
        }
        return memberAddress;
    }
}
